/*****************************************************************
 * Copyright (C) Gasgoo Corporation. All rights reserved.
 * 
 * Author:   Jack Jiang
 * Create Date:  08/26/2006
 * Usage:
 *
 * RevisionHistory
 * Date         Author               Description
 * 
*****************************************************************/

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;

using Microsoft.Practices.EnterpriseLibrary.Data;

using ZJFramework.Entity;

namespace ZJFramework.DataAccess
{
	
	/// <summary>
	/// 
	/// </summary>
	public class DataCommand : ICloneable
	{
		protected DbCommand m_DbCommand;
		protected string m_DatabaseName;

		#region constructors
		
		internal DataCommand(string databaseName, DbCommand command)
		{
			m_DatabaseName = databaseName;
			m_DbCommand = command;
		}

		private DataCommand()
		{
		}

		public object Clone()
		{
			DataCommand cmd = new DataCommand();
			if (m_DbCommand != null)
			{
				if (m_DbCommand is ICloneable)
				{
					cmd.m_DbCommand = ((ICloneable)m_DbCommand).Clone() as DbCommand;
				}
				else
				{
					throw new ApplicationException("A class that implements IClonable is expected.");
				}
			}
			cmd.m_DatabaseName = m_DatabaseName;
			return cmd;
		}

		protected Database ActualDatabase
		{
			// Note: use late binding to reflect the real configuration.
			get { return DatabaseManager.GetDatabase(m_DatabaseName); }
		}
		#endregion

		#region parameters
		/// <summary>
		/// get a parameter value
		/// </summary>
		/// <param name="paramName"></param>
		/// <returns></returns>
		public Object GetParameterValue(string paramName)
		{
			return ActualDatabase.GetParameterValue(m_DbCommand, paramName);
		}
		
		/// <summary>
		/// set a parameter value 
		/// </summary>
		/// <param name="paramName"></param>
		/// <param name="val"></param>
		public void SetParameterValue(string paramName, Object val)
		{
			ActualDatabase.SetParameterValue(m_DbCommand, paramName, val);
		}

        /// <summary>
        /// replace a colummn name using a parameter value 
        /// </summary>
        /// <param name="paramName"></param>
        /// <param name="val"></param>
        public void ReplaceParameterValue(string paramName, string paramValue)
        {
            if (null != m_DbCommand) m_DbCommand.CommandText = m_DbCommand.CommandText.Replace(paramName, paramValue);
        }
		#endregion

		#region execution
		/// <summary>
		/// Executes the scalar.
		/// Throws an exception if an error occurs.
		/// </summary>
		/// <returns></returns>
		public T ExecuteScalar<T>()
		{
			try
			{
				return (T)ActualDatabase.ExecuteScalar(m_DbCommand);
			}
			catch(Exception ex)
			{
				DataAccessLogger.LogExecutionError(m_DbCommand,ex);
				throw;
			}
		}

		/// <summary>
		/// Executes the scalar.
		/// </summary>
		/// <returns></returns>
		public Object ExecuteScalar()
		{
			try
			{
				return ActualDatabase.ExecuteScalar(m_DbCommand);
			}
			catch (Exception ex)
			{
				DataAccessLogger.LogExecutionError(m_DbCommand,ex);
				throw;
			}
		}

		/// <summary>
		/// returns the number of rows affected.
		/// </summary>
		/// <returns></returns>
		public int ExecuteNonQuery()
		{
			try
			{
				return ActualDatabase.ExecuteNonQuery(m_DbCommand);
			}
			catch (Exception ex)
			{
				DataAccessLogger.LogExecutionError(m_DbCommand,ex);
				throw;
			}
		}

		/// <summary>
		/// Executes the entity.
		/// Returns null if no entity is returned or the execution failed.
		/// </summary>
		/// <returns></returns>
		public T ExecuteEntity<T>() where T : class, new()
		{
			IDataReader reader = null;
			try
			{
				reader = ActualDatabase.ExecuteReader(m_DbCommand);
				if (reader.Read())
				{
					return EntityBuilder.BuildEntity<T>(reader);
				}
				else
				{
					return null;
				}
			}
			catch (Exception ex)
			{
				DataAccessLogger.LogExecutionError(m_DbCommand,ex);
                throw;
			}
			finally
			{
				if (reader != null)
				{
					reader.Dispose();
				}
			}
		}

		/// <summary>
		/// Executes the entity list.
		/// Returns an empty list if no entity is returned or the execution fails.
		/// </summary>
		/// <returns></returns>
		public List<T> ExecuteEntityList<T>() where T : class, new()
		{
			IDataReader reader = null;
			try
			{
				reader = ActualDatabase.ExecuteReader(m_DbCommand);
				List<T> list = new List<T>();
				while (reader.Read())
				{
					T entity = EntityBuilder.BuildEntity<T>(reader);
					list.Add(entity);
				}
				return list;
			}
			catch (Exception ex)
			{
				DataAccessLogger.LogExecutionError(m_DbCommand,ex);
                throw;
			}
			finally
			{
				if (reader != null)
				{
					reader.Dispose();
				}
			}
		}

        public K ExecuteEntityCollection<T, K>() where T : class, new() where K : ICollection<T>, new()
        {
            IDataReader reader = null;
            try
            {
                reader = ActualDatabase.ExecuteReader(m_DbCommand);
                ICollection<T> list = new K();
                while (reader.Read())
                {
                    T entity = EntityBuilder.BuildEntity<T>(reader);
                    list.Add(entity);
                }
                return (K)list;
            }
            catch (Exception ex)
            {
                DataAccessLogger.LogExecutionError(m_DbCommand, ex);
                throw;
            }
            finally
            {
                if (reader != null)
                {
                    reader.Dispose();
                }
            }
        }

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		/// <remarks>Use with caution. Remember to dispose the returned reader.</remarks>
		public IDataReader ExecuteDataReader()
		{
			try
			{
				return ActualDatabase.ExecuteReader(m_DbCommand);
			}
			catch (Exception ex)
			{
				DataAccessLogger.LogExecutionError(m_DbCommand,ex);
				throw;
			}
		}

		public DataSet ExecuteDataSet()
		{
			try
			{
				return ActualDatabase.ExecuteDataSet(m_DbCommand);
			}
			catch (Exception ex)
			{
				DataAccessLogger.LogExecutionError(m_DbCommand,ex);
				throw;
			}
		}
		#endregion
	}
}
